home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 1997 #1
/
Amiga Plus CD - 1997 - No. 01.iso
/
pd
/
programmierung
/
oberonv4
/
demos
/
crazyfiller.mod
(
.txt
)
< prev
next >
Wrap
Oberon Text
|
1996-04-02
|
16KB
|
356 lines
Syntax10.Scn.Fnt
Syntax10b.Scn.Fnt
InfoElems
Alloc
Syntax10.Scn.Fnt
StampElems
Alloc
2 Apr 96
"Title": CrazyFiller
"Author": Christoph Steindl (CS)
"Abstract": Implements a new handler for the filler viewers. Filler viewers are dummy viewers which are
visible if no other viewers are on the screen (as well in the user track as in the system track). Then the
filler viewers are painted with Mandlebrot sets. You can zoom into the figures selecting a rectangular
area with the left mouse. You can restore the initial figure by pressing the setup button.
"Keywords": filler
"Version": 1.0
"From": 02.02.95 16:26:50
"Until":
"Changes": selection is restricted so that zoomed area fits into the filler viewer without distortion
"Hints": Use System.Open CrazyFiller.Tool
Syntax10i.Scn.Fnt
FoldElems
Syntax10.Scn.Fnt
redraw
Syntax10.Scn.Fnt
define new zooming area
Syntax10.Scn.Fnt
restore to full size
MODULE CrazyFiller;
(* Christoph Steindl (CS) 02.02.95 - 10 Feb 95 *)
IMPORT Display, Viewers, Oberon, In, Out, Input;
CONST
ML = 2; MM = 1; MR = 0; (* mouse keys *)
filler = 1;
bound = 10;
CrazyFiller* = POINTER TO CrazyFillerDesc;
Drawer* = POINTER TO DrawerDesc;
Region* = POINTER TO RegionDesc;
DrawerDesc* = RECORD (Oberon.TaskDesc)
filler: CrazyFiller;
dx, dy: LONGREAL;
END;
CrazyFillerDesc* = RECORD;
vwr: Viewers.Viewer;
regions: Region;
drawer: Drawer;
xMin, xMax, yMin, yMax: LONGREAL
END;
RegionDesc* = RECORD
x, y, w, h: INTEGER;
next: Region
END;
fillerHandler: Display.Handler;
userFiller, systemFiller: CrazyFiller;
maxIter*: INTEGER;
regsPerCycle*: INTEGER;
PROCEDURE Min(x, y: INTEGER): INTEGER;
BEGIN
IF x < y THEN RETURN x ELSE RETURN y END
END Min;
PROCEDURE Max(x, y: INTEGER): INTEGER;
BEGIN
IF x > y THEN RETURN x ELSE RETURN y END
END Max;
PROCEDURE DrawMandelbrodt;
VAR this: Drawer; p, q, h1, h2, x, y, x0, y0: LONGREAL; filler: CrazyFiller;
region: Region; k1, k2, k3, k4, k5, i, j, count: INTEGER; allBlack: BOOLEAN;
PROCEDURE Dot (col, x, y: INTEGER);
BEGIN
IF col = maxIter THEN
Display.ReplConst(Display.white, x, y, 1, 1, Display.replace)
ELSE
Display.ReplConst(col MOD 15, x, y, 1, 1, Display.replace)
END
END Dot;
PROCEDURE Eval (i, j: INTEGER; VAR k: INTEGER);
BEGIN
k := 0; x := 0; y := 0;
p := filler.xMin + (i - filler.vwr.X) * this.dx; q := filler.yMin + (j - filler.vwr.Y) * this.dy;
REPEAT
h1 := x * x; h2 := y * y;
x0 := h1 - h2 + p; y0 := 2 * x * y + q;
x := x0; y := y0; INC(k)
UNTIL (k >= maxIter) OR (h1 + h2 > bound);
END Eval;
PROCEDURE Divide (x, y, w, h: INTEGER; VAR regions: Region);
VAR xHalf, yHalf: INTEGER; tmp: Region;
BEGIN
xHalf := w DIV 2; yHalf := h DIV 2;
IF xHalf # 0 THEN
IF yHalf # 0 THEN
NEW(tmp); tmp.x := x; tmp.y := y; tmp.w := xHalf; tmp.h := yHalf;
tmp.next := regions; regions := tmp;
NEW(tmp); tmp.x := x + xHalf; tmp.y := y; tmp.w := w - xHalf; tmp.h := yHalf;
tmp.next := regions; regions := tmp;
NEW(tmp); tmp.x := x; tmp.y := y + yHalf; tmp.w := xHalf; tmp.h := h - yHalf;
tmp.next := regions; regions := tmp;
NEW(tmp); tmp.x := x + xHalf; tmp.y := y + yHalf; tmp.w := w - xHalf; tmp.h := h - yHalf;
tmp.next := regions; regions := tmp;
ELSE
NEW(tmp); tmp.x := x; tmp.y := y; tmp.w := xHalf; tmp.h := 1;
tmp.next := regions; regions := tmp;
NEW(tmp); tmp.x := x + xHalf; tmp.y := y; tmp.w := w - xHalf; tmp.h := 1;
tmp.next := regions; regions := tmp;
END
ELSE
IF yHalf # 0 THEN
NEW(tmp); tmp.x := x; tmp.y := y; tmp.w := 1; tmp.h := yHalf;
tmp.next := regions; regions := tmp;
NEW(tmp); tmp.x := x; tmp.y := y + yHalf; tmp.w := 1; tmp.h := h - yHalf;
tmp.next := regions; regions := tmp;
ELSE
Eval(x, y, xHalf);
Dot(xHalf, x, y)
END
END
END Divide;
BEGIN
this := Oberon.CurTask(Drawer); filler := this.filler;
region := filler.regions; filler.regions := filler.regions.next;
count := regsPerCycle;
WHILE (count > 0) & (region # NIL) DO
Eval(region.x, region.y, k1); Eval(region.x + region.w - 1, region.y, k2);
Eval(region.x, region.y + region.h - 1, k3); Eval(region.x + region.w - 1, region.y + region.h - 1, k4);
Dot(k1, region.x, region.y); Dot(k2, region.x + region.w - 1, region.y);
Dot(k3, region.x, region.y + region.h - 1); Dot(k4, region.x + region.w - 1, region.y + region.h - 1);
allBlack := (k1 = k2) & (k2 = k3) & (k3 = k4);
FOR i := region.x + 1 TO region.x + region.w - 2 DO
Eval(i, region.y, k5); Dot(k5, i, region.y); allBlack := allBlack & (k5 = k1);
Eval(i, region.y + region.h - 1, k5); Dot(k5, i, region.y + region.h - 1); allBlack := allBlack & (k5 = k1)
END;
FOR j := region.y + 1 TO region.y + region.h - 2 DO
Eval(region.x, j, k5); Dot(k5, region.x, j); allBlack := allBlack & (k5 = k1);
Eval(region.x + region.w - 1, j, k5); Dot(k5, region.x + region.w - 1, j); allBlack := allBlack & (k5 = k1)
END;
IF allBlack & (region.w > 2) & (region.h > 2) THEN
IF k1 = maxIter THEN
Display.ReplConst(Display.white, region.x + 1, region.y + 1, region.w - 2, region.h - 2, Display.replace)
ELSE
Display.ReplConst(k1 MOD 15, region.x + 1, region.y + 1, region.w - 2, region.h - 2, Display.replace)
END
ELSIF (region.w > 2) & (region.h > 2) THEN
Divide(region.x + 1, region.y + 1, region.w - 2, region.h - 2, filler.regions);
END;
DEC(count); region := filler.regions;
IF (filler.regions # NIL) & (count > 0) THEN filler.regions := filler.regions.next END
END;
IF region = NIL THEN Oberon.Remove(this) END
END DrawMandelbrodt;
PROCEDURE DragRect (filler: CrazyFiller; f: Display.Frame; x0, y0, x1, y1: INTEGER; VAR x2, y2: INTEGER;
VAR keysum: SET);
VAR keys: SET; x, y: INTEGER;
PROCEDURE ReplConst(x, y, w, h: INTEGER);
BEGIN
IF w < 0 THEN x := x + w; w := - w END;
IF h < 0 THEN y := y + h; h := - h END;
IF (w # 0) & (h # 0) THEN Display.ReplConst(Display.white, x, y, w, h, Display.invert) END
END ReplConst;
PROCEDURE FlipRect(x0, y0, x1, y1, x2, y2: INTEGER);
BEGIN
ReplConst(x0 + 1, y1, x1 - x0 - 2, 1);
ReplConst(x1 - 1, y1, 1, y0 - y1);
ReplConst(x1 - 1, y0 - 1, x2 - x1, 1);
ReplConst(x2 - 1, y2, 1, y0 - y2);
ReplConst(x0 + 1, y2, x2 - x0 - 2, 1);
ReplConst(x0, y2, 1, y1 - y2)
END FlipRect;
BEGIN
keys := keysum;
FlipRect(x0, y0, x0 + 1, y0 - 1, x1, y1); (* draw initial rectangle *)
WHILE keys # {} DO
Input.Mouse(keys, x, y);
Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y);
keysum := keysum + keys;
x2 := Min(Max(x, f.X), f.X + f.W); (* confine x2 to frame f *)
y2 := Min(Max(y, f.Y), f.Y + f.H); (* confine y2 to frame f *)
IF y2 < SHORT(ENTIER(y0 - ABS(x2 - x0) * filler.vwr.H / filler.vwr.W + 0.5)) THEN
y2 := SHORT(ENTIER(y0 - ABS(x2 - x0) * filler.vwr.H / filler.vwr.W + 0.5))
ELSIF y2 > SHORT(ENTIER(y0 + ABS(x2 - x0) * filler.vwr.H / filler.vwr.W + 0.5)) THEN
y2 := SHORT(ENTIER(y0 + ABS(x2 - x0) * filler.vwr.H / filler.vwr.W + 0.5))
END;
IF x2 < SHORT(ENTIER(x0 - ABS(y2 - y0) * filler.vwr.W / filler.vwr. H + 0.5)) THEN
x2 := SHORT(ENTIER(x0 - ABS(y2 - y0) * filler.vwr.W / filler.vwr. H + 0.5))
ELSIF x2 > SHORT(ENTIER(x0 + ABS(y2 - y0) * filler.vwr.W / filler.vwr.H + 0.5)) THEN
x2 := SHORT(ENTIER(x0 + ABS(y2 - y0) * filler.vwr.W / filler.vwr. H + 0.5))
END;
IF (x2 # x1) OR (y2 # y1) THEN
FlipRect(x0, y0, x1, y1, x2, y2);
x1 := x2; y1 := y2
END
END;
FlipRect(x0, y0, x0 + 1, y0 - 1, x1, y1) (* erase spanned rectangle *)
END DragRect;
PROCEDURE InitDrawer* (VAR drawer: DrawerDesc; W, H: INTEGER;
filler: CrazyFiller; draw: Oberon.Handler);
BEGIN
drawer.handle := draw; drawer.safe := FALSE;
drawer.filler := filler;
drawer.dx := (drawer.filler.xMax - drawer.filler.xMin) / W;
drawer.dy := (drawer.filler.yMax - drawer.filler.yMin) / H;
END InitDrawer;
PROCEDURE InitFiller (filler: CrazyFiller; vwr: Viewers.Viewer);
BEGIN
filler.xMin := -2.25; filler.xMax := 0.75;
filler.yMin := -1.125; filler.yMax := 1.125;
filler.vwr := vwr;
END InitFiller;
PROCEDURE InstallCustomHandler* (h: Display.Handler);
VAR m: Viewers.ViewerMsg;
BEGIN
IF h = fillerHandler THEN RETURN END;
m.id := Viewers.restore;
IF userFiller.regions # NIL THEN userFiller.regions := NIL; Oberon.Remove(userFiller.drawer) END;
userFiller.vwr.handle := h; userFiller.vwr.handle(userFiller.vwr, m);
IF systemFiller.regions # NIL THEN systemFiller.regions := NIL; Oberon.Remove(systemFiller.drawer) END;
systemFiller.vwr.handle := h; systemFiller.vwr.handle(systemFiller.vwr, m)
END InstallCustomHandler;
PROCEDURE DefaultHandler* (f: Display.Frame; VAR m: Display.FrameMsg);
BEGIN
WITH f: Viewers.Viewer DO
IF m IS Oberon.InputMsg THEN
WITH m: Oberon.InputMsg DO
IF m.id=Oberon.track THEN Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, m.X, m.Y) END
END
ELSIF m IS Oberon.ControlMsg THEN
WITH m: Oberon.ControlMsg DO
IF m.id=Oberon.mark THEN Oberon.DrawCursor(Oberon.Pointer, Oberon.Star, m.X, m.Y) END
END
ELSIF m IS Viewers.ViewerMsg THEN
WITH m: Viewers.ViewerMsg DO
IF (m.id=Viewers.restore) & (f.W > 0) & (f.H > 0) THEN Oberon.RemoveMarks(f.X, f.Y, f.W, f.H);
Display.ReplConst(Display.black, f.X, f.Y, f.W, f.H, Display.replace)
ELSIF (m.id=Viewers.modify) & (m.Y < f.Y) THEN Oberon.RemoveMarks(f.X, m.Y, f.W, f.Y-m.Y);
Display.ReplConst(Display.black, f.X, m.Y, f.W, f.Y-m.Y, Display.replace)
END
END
END
END DefaultHandler;
PROCEDURE CrazyHandler* (f: Display.Frame; VAR m: Display.FrameMsg);
VAR drawer: Drawer; x, y: INTEGER; filler, oldFiller: CrazyFiller; redrawMsg: Viewers.ViewerMsg;
PROCEDURE Redraw(y, h: INTEGER);
VAR region: Region;
BEGIN
IF filler.regions # NIL THEN filler.regions := NIL; Oberon.Remove(filler.drawer) END;
Oberon.RemoveMarks(f.X, f.Y, f.W, f.H);
NEW(drawer); InitDrawer(drawer^, f.W, h, filler, DrawMandelbrodt);
filler.drawer := drawer;
NEW(region); region.x := f.X; region.y := y; region.w := f.W; region.h := h;
filler.regions := region;
Display.ReplConst(Display.black, f.X, y, f.W, h, Display.replace);
Oberon.Install(drawer)
END Redraw;
BEGIN
WITH f: Viewers.Viewer DO
WITH m: Viewers.ViewerMsg DO
IF f.X = 0 THEN filler := userFiller ELSE filler := systemFiller END;
IF m.id = Viewers.restore THEN
IF (f.W > 0) & (f.H > 0) THEN Redraw(f.Y, f.H)
ELSE IF filler.regions # NIL THEN filler.regions := NIL; Oberon.Remove(filler.drawer) END
END
ELSIF m.id = Viewers.modify THEN Redraw(m.Y, m.H)
ELSIF m.id = Viewers.suspend THEN
IF filler.regions # NIL THEN filler.regions := NIL; Oberon.Remove(filler.drawer) END
END
| m: Oberon.InputMsg DO
IF m.id = Oberon.track THEN (* mouse event *)
Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, m.X, m.Y);
IF ML IN m.keys THEN
IF m.X < userFiller.vwr.X + userFiller.vwr.W THEN (* click in user filler *)
filler := userFiller
ELSE
filler := systemFiller
END;
DragRect(filler, f, m.X, m.Y, m.X + 2, m.Y - 2, x, y, m.keys); (* m.X, m.Y is the upper
left corner; x, y is the lower right corner *)
IF m.keys # {ML, MM, MR} THEN
NEW(oldFiller); oldFiller^ := filler^;
filler.yMin := oldFiller.yMin + (oldFiller.yMax - oldFiller.yMin) / oldFiller.vwr.H * (Min(y, m.Y) - oldFiller.vwr.Y);
filler.yMax := oldFiller.yMin + (oldFiller.yMax - oldFiller.yMin) / oldFiller.vwr.H * (Max(y, m.Y) - oldFiller.vwr.Y);
filler.xMin := oldFiller.xMin + (oldFiller.xMax - oldFiller.xMin) / oldFiller.vwr.W * (Min(x, m.X) - oldFiller.vwr.X);
filler.xMax := oldFiller.xMin + (oldFiller.xMax - oldFiller.xMin) / oldFiller.vwr.W * (Max(x, m.X) - oldFiller.vwr.X);
redrawMsg.id := Viewers.restore;
filler.vwr.handle(filler.vwr, redrawMsg);
END
END
ELSE DefaultHandler(f, m)
END
| m: Oberon.ControlMsg DO
IF m.id = Oberon.neutralize THEN
userFiller.xMin := -2.25; userFiller.xMax := 0.75;
userFiller.yMin := -1.125; userFiller.yMax := 1.125;
systemFiller.xMin := -2.25; systemFiller.xMax := 0.75;
systemFiller.yMin := -1.125; systemFiller.yMax := 1.125;
redrawMsg.id := Viewers.restore;
userFiller.vwr.handle(userFiller.vwr, redrawMsg);
systemFiller.vwr.handle(systemFiller.vwr, redrawMsg)
ELSE DefaultHandler(f, m)
END
ELSE DefaultHandler(f, m)
END
END CrazyHandler;
PROCEDURE InstallDefault*;
BEGIN InstallCustomHandler(DefaultHandler) END InstallDefault;
PROCEDURE InstallCrazy*;
BEGIN InstallCustomHandler(CrazyHandler) END InstallCrazy;
PROCEDURE SetMaxIter*;
BEGIN
In.Open; In.Int(maxIter)
END SetMaxIter;
PROCEDURE SetRegsPerCycle*;
BEGIN
In.Open; In.Int(regsPerCycle)
END SetRegsPerCycle;
PROCEDURE ShowParams*;
BEGIN
IF (userFiller.vwr # NIL) & (userFiller.vwr.H > 0) THEN
Out.Ln; Out.String("User filler:");
Out.Ln; Out.String(" Range:");
Out.Ln; Out.String(" xMin = "); Out.LongReal(userFiller.xMin, 20);
Out.String(", xMax = "); Out.LongReal(userFiller.xMax, 20);
Out.Ln; Out.String(" yMin = "); Out.LongReal(userFiller.yMin, 20);
Out.String(", yMax = "); Out.LongReal(userFiller.yMax, 20);
Out.Ln; Out.String(" Height: "); Out.Int(userFiller.vwr.H, 0);
Out.Ln; Out.String(" Width: "); Out.Int(userFiller.vwr.W, 0);
Out.Ln; Out.String(" Iterations: "); Out.Int(maxIter, 0);
Out.Ln; Out.String(" Bound: "); Out.Int(bound, 0);
Out.Ln; Out.String(" Rectangles per cycle: "); Out.Int(regsPerCycle, 0)
END;
IF (systemFiller.vwr # NIL) & (systemFiller.vwr.H > 0) THEN
Out.Ln; Out.String("System filler:");
Out.Ln; Out.String(" Range:");
Out.Ln; Out.String(" xMin = "); Out.LongReal(systemFiller.xMin, 20);
Out.String(", xMax = "); Out.LongReal(systemFiller.xMax, 20);
Out.Ln; Out.String(" yMin = "); Out.LongReal(systemFiller.yMin, 20);
Out.String(", yMax = "); Out.LongReal(systemFiller.yMax, 20);
Out.Ln; Out.String(" Height: "); Out.Int(systemFiller.vwr.H, 0);
Out.Ln; Out.String(" Width: "); Out.Int(systemFiller.vwr.W, 0);
Out.Ln; Out.String(" Iterations: "); Out.Int(maxIter, 0);
Out.Ln; Out.String(" Bound: "); Out.Int(bound, 0);
Out.Ln; Out.String(" Rectangles per cycle: "); Out.Int(regsPerCycle, 0)
END ShowParams;
PROCEDURE Init;
VAR cur: Viewers.Viewer;
BEGIN
fillerHandler := NIL; maxIter := 100; regsPerCycle := 20;
NEW(userFiller); NEW(systemFiller);
cur := Viewers.This(0, 0); WHILE cur.state # filler DO cur := Viewers.Next(cur) END;
InitFiller(userFiller, cur);
cur := Viewers.This(cur.W, 0); WHILE cur.state # filler DO cur := Viewers.Next(cur) END;
InitFiller(systemFiller, cur)
END Init;
BEGIN
Init
END CrazyFiller.InstallCrazy CrazyFiller.InstallDefault CrazyFiller.ShowParams
CrazyFiller.SetMaxIter 30